package com.zhouhailin.reflection.question;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 反射问题的引入
 *
 * @Author zhouhailin
 * @date 2023/2/3 9:49
 */
@SuppressWarnings({"all"})
public class ReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {

        // 根据配置文件 re.properties 指定信息, 创建 Cat 对象并调用方法 hi
        // 老韩回忆
        // 传统的方式 new 对象 -》 调用方法
        // Cat cat = new Cat();
        // cat.hi(); ===> cat.cry() 修改源码. //我们尝试做一做 -> 明白反射
        // 1. 使用 Properties 类, 可以读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("D:\\Java\\Code-Demo\\Java-Demo\\Reflection-Demo\\src\\main\\resources\\re.properties"));
        // "hi" System.out.println("classfullpath=" + classfullpath);
        String methodName = properties.get("method").toString();
        System.out.println("methodName: " + methodName);
        String classfullpath = properties.get("classfullpath").toString();
        System.out.println("classfullpath：" + classfullpath);
        System.out.println("===============================================================================");
        // System.out.println("method=" + methodName);


        // 2. 创建对象 , 传统的方法，行不通 =》 反射机制
        // new classfullpath();


        // 3. 使用反射机制解决
        // (1) 加载类, 返回 Class 类型的对象 cls
        Class cls = Class.forName(classfullpath);
        // (2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例
        Object o = cls.newInstance();
        // 运行类型
        System.out.println("o 的运行类型=" + o.getClass());
        // (3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象
        // 即：在反射中，可以把方法视为对象（万物皆对象）
        Method method1 = cls.getMethod(methodName);
        // (4) 通过 method1 调用方法: 即通过方法对象来实现调用方法
        System.out.println("===============================================================================");
        // 传统方法： 对象.方法() ,
        // 反射机制： 方法.invoke(对象)
        method1.invoke(o);


        // 4、反射机制：获取成员变量
        System.out.println("===============================================================================");
        // getField 不能得到私有的属性
        Field ageField = cls.getField("age");
        // 传统写法：对象.成员变量
        // 反射写法：成员变量对象.get(对象)
        System.out.println(ageField.get(o));

        // 5、反射机制：获取构造器
        // getConstructor()中，可以指定构造器参数类型，也可以不指定参数类型
        System.out.println("===============================================================================");
        // 5.1）不指定指定参数类型
        Constructor constructor_1 = cls.getConstructor();
        System.out.println(constructor_1);

        // 5.2）指定指定参数类型
        Constructor constructor_2 = cls.getConstructor(String.class, Integer.class);
        System.out.println(constructor_2);
    }
}
